#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Ticker.h>

#define PIN_LED   2
#define PIN_RELAY 5
#define PIN_TEMP   4
#define PIN_FEED   0

// WiFi信息
const char *ssid = "WiFi名称"; // WiFi名称
const char *password = "WiFi密码";  // WiFi密码

// MQTT代理服务器信息
const char *mqtt_broker = "127.0.0.1";
const char *pubTopic = "1661084679024906242/pub";
const char *subTopic = "1661084679024906242/sub";
const char *client_id = "1661084679024906242";
const char *mqtt_username = "1661084679024906242";
const char *mqtt_password = "fMA0GCSqGSIb3DQEBAQU";
const int mqtt_port = 1883;

WiFiClient espClient;
PubSubClient client(espClient);
Ticker flipper;  //实例化定时器对象

//返回 0：初始化成功
unsigned char Init_QT18B20(void)
{
  unsigned char dat;

  pinMode(PIN_TEMP, OUTPUT);      //输出模式
  digitalWrite(PIN_TEMP,HIGH);      //TEMP拉高
  delayMicroseconds(13);        //13微秒
  digitalWrite(PIN_TEMP,LOW);      //TEMP拉低
  delayMicroseconds(642);        //单片机拉低总线:>480us。642us
  digitalWrite(PIN_TEMP,HIGH);      //TEMP拉低
  delayMicroseconds(60);       //释放总线，在中间位置读取是否有器件响应。60us
  pinMode(PIN_TEMP, INPUT);      //输入模式
  delayMicroseconds(210);         //210us
  dat = digitalRead(PIN_TEMP); //读低电平
  pinMode(PIN_TEMP, OUTPUT);      //输出模式
  return dat;
}

//读1字节温度数据
unsigned char ReadOneChar(void)
{
  unsigned char i;
  unsigned char date = 0;
  for(i=8;i>0;i--)
  {
    pinMode(PIN_TEMP, OUTPUT);      //输出模式
    digitalWrite(PIN_TEMP,LOW);      //TEMP拉低
    delayMicroseconds(5);         //5us
    digitalWrite(PIN_TEMP,HIGH);      //TEMP拉高
    delayMicroseconds(5);         //5us
    pinMode(PIN_TEMP, INPUT);      //输入模式
    date >>= 1;
    if(digitalRead(PIN_TEMP))
    {
      date |= 0x80;
    }
    pinMode(PIN_TEMP, OUTPUT);      //输出模式
    digitalWrite(PIN_TEMP,HIGH);      //TEMP拉高
    delayMicroseconds(45);         //45us
  }
  return date;
}

//写1字节温度数据
void WriteOneChar(unsigned char date)
{
  unsigned char i;
  unsigned char textb;
  for(i = 8;i > 0;i--)
  {
    textb = date&0x01;
    date = date >> 1;
    if(textb)
    {
      pinMode(PIN_TEMP, OUTPUT);      //输出模式
      digitalWrite(PIN_TEMP,LOW);      //TEMP拉低
      delayMicroseconds(2);         //大于1us
      digitalWrite(PIN_TEMP,HIGH);      //TEMP拉高
      delayMicroseconds(90); //至少60us,90us
    }
    else
    {
      pinMode(PIN_TEMP, OUTPUT);      //输出模式
      digitalWrite(PIN_TEMP,LOW);      //TEMP拉低
      delayMicroseconds(90); //至少60us,90us
      digitalWrite(PIN_TEMP,HIGH);      //TEMP拉高
      delayMicroseconds(2);         //大于1us
    }
  }
}

float ReadTemp(void)
{
  unsigned int temp = 0;
  unsigned int templ;
  unsigned int temph;
  float i,j;
  Init_QT18B20();
  delayMicroseconds(15);         //大于10us
  WriteOneChar(0xcc);
  WriteOneChar(0x44);

  Init_QT18B20();
  WriteOneChar(0xcc);
  WriteOneChar(0xbe);
  templ = ReadOneChar();
  temph = ReadOneChar();
  temp = temph;
  temp <<= 8;
  temp |= templ;
  i = temp;
  j = 0.0625*i;
  return j;
}

//中断服务程序
void flip(){
    // 组织数据
    // 创建一个JSON对象
    StaticJsonBuffer<200> jsonBuffer;
    JsonObject& root = jsonBuffer.createObject();
    root["temp"] = String(ReadTemp(), 2);  //温度检测
    root["relay"] = digitalRead(PIN_RELAY);
    char *pubMessage = (char*)malloc(root.measurePrettyLength()+1);
    root.printTo(pubMessage,root.measurePrettyLength()+1);
    client.publish(pubTopic, pubMessage);
    Serial.print("发布主题: ");
    Serial.println(pubTopic);
    Serial.print("消息内容:");
    Serial.println(pubMessage);
    Serial.println("-----------------------");
    free(pubMessage);
}

void reconnect(){
      while (!client.connected()) {
        Serial.printf("%s设备尝试连接MQTT代理\n", client_id);
        if (client.connect(client_id, mqtt_username, mqtt_password)) {
            Serial.println("MQTT代理服务器连接成功");
                //消息订阅
            client.subscribe(subTopic);
        } else {
            Serial.print("尚未连接成功");
            Serial.println(client.state());
            delay(2000);
        }
    }
}

void setup() {
    pinMode(PIN_LED, OUTPUT);        //输出模式
    pinMode(PIN_RELAY, OUTPUT);      //输出模式
    digitalWrite(PIN_LED,HIGH);      //LED默认关闭
    digitalWrite(PIN_RELAY,LOW );    //继电器默认关闭
    // 设置串口波特率115200;
    Serial.begin(115200);
    //断开网络连接的状况，反复尝试自动重连
    WiFi.setAutoReconnect(true);
    // 尝试连接WiFi网络
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        digitalWrite(PIN_LED, LOW);    //打开LED         
        delay(500); //延时1S
        digitalWrite(PIN_LED, HIGH);
        delay(500); //延时1S
        Serial.println("正在连接WiFi...");
    }
    digitalWrite(PIN_LED, HIGH);    //关闭LED 
    Serial.println("连接WiFi网络成功");
    //连接到mqtt代理服务器
    client.setServer(mqtt_broker, mqtt_port);
    client.setCallback(callback);
    // 消息发布
    flipper.attach(1, flip);//每隔2秒执行一次回调函数    
}

void callback(char *topic, byte *payload, unsigned int length) {
    Serial.print("订阅主题: ");
    Serial.println(subTopic);
    char *subMessage = (char*)malloc(length+1);
    memset(subMessage,'\0',length+1);
    strncpy(subMessage, (char*)payload, length);
    subMessage[length]='\0';
    Serial.print("消息内容:");
    Serial.println(subMessage);
    
    StaticJsonBuffer<200> jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject(subMessage);
    const char* relay = root["relay"];
    Serial.print("设备响应:");
    if(strcmp(relay,"0") == 0){
      //继电器关闭
      digitalWrite(PIN_RELAY,LOW );
      Serial.println("继电器关闭");
    }else if(strcmp(relay,"1") == 0){
      //继电器开启
      digitalWrite(PIN_RELAY,HIGH );
      delay(2000);         //0.5s
      pinMode(PIN_FEED, OUTPUT);
      digitalWrite(PIN_FEED,HIGH);
      pinMode(PIN_FEED, INPUT);      //输入模式
      Serial.println("继电器开启");
    }
    
    free(subMessage);
    Serial.println("-----------------------");
}

void loop() {
     if(digitalRead(PIN_FEED) == 0){
      Serial.println("继电器关闭");
      digitalWrite(PIN_RELAY,LOW );
      pinMode(PIN_FEED, OUTPUT);
      digitalWrite(PIN_FEED,HIGH);
      pinMode(PIN_FEED, INPUT);
    }
  
    if(!client.connected()){
      reconnect();
    }
    client.loop();
}
